package com.ls.lspicturebackend.aop;

import com.ls.lspicturebackend.annotation.SpaceAuthCheck;
import com.ls.lspicturebackend.common.DeleteRequest;
import com.ls.lspicturebackend.exception.BusinessException;
import com.ls.lspicturebackend.exception.ErrorCode;
import com.ls.lspicturebackend.exception.ThrowUtils;
import com.ls.lspicturebackend.model.dto.spaceuser.SpaceUserAddRequest;
import com.ls.lspicturebackend.model.dto.spaceuser.SpaceUserEditRequest;
import com.ls.lspicturebackend.model.dto.spaceuser.SpaceUserQueryRequest;
import com.ls.lspicturebackend.model.entity.SpaceUser;
import com.ls.lspicturebackend.model.entity.User;
import com.ls.lspicturebackend.model.enums.SpaceRoleEnum;
import com.ls.lspicturebackend.service.SpaceUserService;
import com.ls.lspicturebackend.service.UserService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;

@Aspect
@Component
public class SpaceAuthInterceptor {

    @Resource
    private UserService userService;

    @Resource
    private SpaceUserService spaceUserService;

    @Around("@annotation(spaceAuthCheck)")
    public Object doInterceptor(ProceedingJoinPoint joinPoint, SpaceAuthCheck spaceAuthCheck) throws Throwable {
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        User loginUser = userService.getLoginUser(request);
        ThrowUtils.throwIf(loginUser == null, ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
        List<String> anyRolesList = Arrays.asList(spaceAuthCheck.anyRoles());
        if (anyRolesList.isEmpty()) {
            return joinPoint.proceed();
        }
        Long userId = loginUser.getId();
        Object arg = joinPoint.getArgs()[0];
        if (arg instanceof SpaceUserAddRequest || arg instanceof SpaceUserQueryRequest) {
            Long spaceId;
            if (arg instanceof SpaceUserAddRequest) {
                spaceId = ((SpaceUserAddRequest) arg).getSpaceId();
            } else {
                spaceId = ((SpaceUserQueryRequest) arg).getSpaceId();
            }
            String userRole = getUserRoleBySpaceId(userId, spaceId);
            if (!anyRolesList.contains(userRole)) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有权限");
            }
            return joinPoint.proceed();
        }
        if (arg instanceof SpaceUserEditRequest || arg instanceof DeleteRequest) {
            Long id;
            if (arg instanceof SpaceUserEditRequest) {
                id = ((SpaceUserEditRequest) arg).getId();
            } else {
                id = ((DeleteRequest) arg).getId();
            }
            String userRole = getUserRoleById(userId, id);
            if (!anyRolesList.contains(userRole)) {
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "没有权限");
            }
            return joinPoint.proceed();
        }
        return joinPoint.proceed();
    }

    private String getUserRoleBySpaceId(Long userId, Long spaceId) {
        return spaceUserService.lambdaQuery()
                .select(SpaceUser::getSpaceRole)
                .eq(SpaceUser::getUserId, userId)
                .eq(SpaceUser::getSpaceId, spaceId)
                .oneOpt()
                .map(SpaceUser::getSpaceRole)
                .orElse(SpaceRoleEnum.VIEWER.getValue());
    }

    private String getUserRoleById(Long userId, Long id) {
        Long spaceId = spaceUserService.lambdaQuery()
                .select(SpaceUser::getSpaceId)
                .eq(SpaceUser::getId, id)
                .oneOpt()
                .map(SpaceUser::getSpaceId)
                .orElse(null);
        if (spaceId == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "无此空间");
        }
        return spaceUserService.lambdaQuery()
                .select(SpaceUser::getSpaceRole)
                .eq(SpaceUser::getUserId, userId)
                .eq(SpaceUser::getSpaceId, spaceId)
                .oneOpt()
                .map(SpaceUser::getSpaceRole)
                .orElse(SpaceRoleEnum.VIEWER.getValue());
    }
}
